package k8s

import (
	"fmt"
	appsv1 "k8s.io/api/apps/v1"
	batchv1 "k8s.io/api/batch/v1"
	batchv1beta1 "k8s.io/api/batch/v1beta1"
	corev1 "k8s.io/api/core/v1"
	rbacv1 "k8s.io/api/rbac/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"strings"
)

type Metadata struct {
	Namespace    string
	WorkloadName string
	Kind         string
	Version      string
}

func NewMetadata() *Metadata {
	return &Metadata{}
}

type ResourceMetricsCore struct {
	CPURequests resource.Quantity
	CPULimits   resource.Quantity
	MemRequests resource.Quantity
	MemLimits   resource.Quantity
	GPURequests resource.Quantity
	GPULimits   resource.Quantity
}

func NewResourceMetricsCore() *ResourceMetricsCore {
	return &ResourceMetricsCore{
		CPURequests: resource.MustParse("0"),
		CPULimits:   resource.MustParse("0"),
		MemRequests: resource.MustParse("0"),
		MemLimits:   resource.MustParse("0"),
		GPURequests: resource.MustParse("0"),
		GPULimits:   resource.MustParse("0"),
	}
}

type ResourceMetrics struct {
	*Metadata
	*ResourceMetricsCore
	HasCPU    bool
	HasMemory bool
	HasGPU    bool
}

func NewEmptyMetrics() *ResourceMetrics {
	return &ResourceMetrics{
		NewMetadata(),
		NewResourceMetricsCore(),
		false,
		false,
		false,
	}
}

func (m *ResourceMetricsCore) Add(other *ResourceMetrics) {
	m.CPURequests.Add(other.CPURequests)
	m.CPULimits.Add(other.CPULimits)
	m.MemRequests.Add(other.MemRequests)
	m.MemLimits.Add(other.MemLimits)
	m.GPURequests.Add(other.GPURequests)
	m.GPULimits.Add(other.GPULimits)
}
func (r ResourceMetrics) PrettyPrint() string {
	var sb strings.Builder

	normalize := func(val string, unit string, raw resource.Quantity) (string, string) {
		if raw.IsZero() {
			return "未做限制", ""
		}
		return val, unit
	}

	// 拆 CPU、Mem
	cpuReqVal, cpuReqUnit := SplitValueUnit(FormatCPU(r.CPURequests))
	cpuLimVal, cpuLimUnit := SplitValueUnit(FormatCPU(r.CPULimits))
	memReqVal, memReqUnit := SplitValueUnit(FormatMemory(r.MemRequests))
	memLimVal, memLimUnit := SplitValueUnit(FormatMemory(r.MemLimits))

	cpuReqVal, cpuReqUnit = normalize(cpuReqVal, cpuReqUnit, r.CPURequests)
	cpuLimVal, cpuLimUnit = normalize(cpuLimVal, cpuLimUnit, r.CPULimits)
	memReqVal, memReqUnit = normalize(memReqVal, memReqUnit, r.MemRequests)
	memLimVal, memLimUnit = normalize(memLimVal, memLimUnit, r.MemLimits)

	// GPU：仅当 FormatGPU 返回 ok==true 才打印
	var gpuReqVal, gpuReqUnit, gpuLimVal, gpuLimUnit string
	gpuPresent := false

	if v, ok := FormatGPU(r.GPURequests); ok {
		gpuReqVal, gpuReqUnit = SplitValueUnit(v)
		gpuPresent = true
	}
	if v, ok := FormatGPU(r.GPULimits); ok {
		gpuLimVal, gpuLimUnit = SplitValueUnit(v)
		gpuPresent = true
	}

	// 计算对齐宽度（不包含 GPU 的“未设置”）
	maxValWidth := maxInt(
		len(cpuReqVal), len(cpuLimVal),
		len(memReqVal), len(memLimVal),
	)

	if gpuPresent {
		maxValWidth = maxInt(
			maxValWidth,
			len(gpuReqVal), len(gpuLimVal),
		)
	}

	sb.WriteString(formatHeader(r))
	sb.WriteString("Resource Metrics:\n")

	sb.WriteString(fmt.Sprintf("  CPU Requests: %*s %s\n", maxValWidth, cpuReqVal, cpuReqUnit))
	sb.WriteString(fmt.Sprintf("  CPU Limits  : %*s %s\n", maxValWidth, cpuLimVal, cpuLimUnit))
	sb.WriteString(fmt.Sprintf("  Mem Requests: %*s %s\n", maxValWidth, memReqVal, memReqUnit))
	sb.WriteString(fmt.Sprintf("  Mem Limits  : %*s %s\n", maxValWidth, memLimVal, memLimUnit))

	if gpuPresent {
		sb.WriteString(fmt.Sprintf("  GPU Requests: %*s %s\n", maxValWidth, gpuReqVal, gpuReqUnit))
		sb.WriteString(fmt.Sprintf("  GPU Limits  : %*s %s\n", maxValWidth, gpuLimVal, gpuLimUnit))
	}

	return sb.String()
}

func formatHeader(r ResourceMetrics) string {
	kindVersion := fmt.Sprintf("%s (%s)", r.Kind, r.Version)

	// 每行真实内容（去掉前缀“│ xxx : ”）
	lines := []string{
		fmt.Sprintf("Namespace : %s", r.Namespace),
		fmt.Sprintf("Kind      : %s", kindVersion),
		fmt.Sprintf("Name      : %s", r.WorkloadName),
	}

	// 找出最长的一行，用来确定框宽度
	maxLen := 0
	for _, line := range lines {
		if l := len([]rune(line)); l > maxLen {
			maxLen = l
		}
	}

	// 框整体宽度（+2 让左右有空隙）
	frameWidth := maxLen + 2

	var sb strings.Builder

	// 顶部线
	sb.WriteString("┌")
	sb.WriteString(strings.Repeat("─", frameWidth))
	sb.WriteString("┐\n")

	// 中间内容
	for _, line := range lines {
		padding := frameWidth - len([]rune(line))
		sb.WriteString("│ ")
		sb.WriteString(line)
		sb.WriteString(strings.Repeat(" ", padding-1))
		sb.WriteString("│\n")
	}

	// 底部线
	sb.WriteString("└")
	sb.WriteString(strings.Repeat("─", frameWidth))
	sb.WriteString("┘\n")

	return sb.String()
}

// 辅助函数，把 "8 核" 或 "15.625 Gi" 拆成 ("8", "核") 或 ("15.625", "Gi")
func SplitValueUnit(s string) (val, unit string) {
	for i, r := range s {
		if !(r >= '0' && r <= '9') && r != '.' {
			return s[:i], strings.TrimSpace(s[i:])
		}
	}
	return s, ""
}

func maxInt(vals ...int) int {
	m := 0
	for _, v := range vals {
		if v > m {
			m = v
		}
	}
	return m
}

type ResponseResourceMetrics struct {
	Items []*ResourceMetrics
	Total *ResourceMetricsCore
	Count int
}

func NewEmptyResponseMetrics() *ResponseResourceMetrics {
	return &ResponseResourceMetrics{
		Items: []*ResourceMetrics{},
		Total: NewResourceMetricsCore(),
		Count: 0,
	}
}
func (m *ResponseResourceMetrics) Add(rm *ResourceMetrics) {
	m.Total.Add(rm)
	m.Items = append(m.Items, rm)
	m.Count++
}

type RequestWorkloads struct {
	WorkloadNames []string
}

func (w *RequestWorkloads) Validate() error {
	if len(w.WorkloadNames) == 0 {
		return fmt.Errorf("workload names must not be empty")
	}
	return nil
}

func NewRequestWorkloads() *RequestWorkloads {
	return &RequestWorkloads{
		WorkloadNames: []string{},
	}
}
func (w *RequestWorkloads) Add(workloadNames ...string) {
	w.WorkloadNames = append(w.WorkloadNames, workloadNames...)
}

func FormatCPU(q resource.Quantity) string {
	cores := q.AsApproximateFloat64()

	// 小于 1，用 m
	if cores < 1 {
		milli := int64(cores * 1000)
		return fmt.Sprintf("%d m", milli)
	}

	// 整数：不带小数
	if cores == float64(int64(cores)) {
		return fmt.Sprintf("%d 核", int64(cores))
	}

	// 非整数：保留两位
	return fmt.Sprintf("%.2f 核", cores)
}

func FormatMemory(q resource.Quantity) string {
	bytes := float64(q.Value()) // bytes

	mi := bytes / (1024 * 1024)
	if mi < 1024 {
		return fmt.Sprintf("%.0f Mi", mi)
	}

	gi := mi / 1024
	if gi < 1024 {
		return fmt.Sprintf("%.3f Gi", gi)
	}

	ti := gi / 1024
	return fmt.Sprintf("%.3f Ti", ti)
}

// GPU: 有值才打印
func FormatGPU(q resource.Quantity) (string, bool) {
	if q.IsZero() {
		return "", false
	}
	v := q.AsApproximateFloat64()
	if v == float64(int64(v)) {
		return fmt.Sprintf("%.0f GPU", v), true
	}
	return fmt.Sprintf("%.3f GPU", v), true
}

func (r *ResponseResourceMetrics) PrettyPrintSummary() string {
	if r.Total == nil {
		return "统计结果：\n无资源数据。\n"
	}

	var sb strings.Builder
	sb.WriteString("统计结果：\n")

	type item struct {
		name string
		val  string
		unit string
	}

	items := []item{}

	val, unit := SplitValueUnit(FormatCPU(r.Total.CPURequests))
	items = append(items, item{"Total CPU Requests", val, unit})

	val, unit = SplitValueUnit(FormatCPU(r.Total.CPULimits))
	items = append(items, item{"Total CPU Limits", val, unit})

	val, unit = SplitValueUnit(FormatMemory(r.Total.MemRequests))
	items = append(items, item{"Total Mem Requests", val, unit})

	val, unit = SplitValueUnit(FormatMemory(r.Total.MemLimits))
	items = append(items, item{"Total Mem Limits", val, unit})

	// GPU 条目只有设置才加入
	if v, ok := FormatGPU(r.Total.GPURequests); ok {
		val, unit := SplitValueUnit(v)
		items = append(items, item{"Total GPU Requests", val, unit})
	}
	if v, ok := FormatGPU(r.Total.GPULimits); ok {
		val, unit := SplitValueUnit(v)
		items = append(items, item{"Total GPU Limits", val, unit})
	}

	// 计算列宽
	maxNameWidth := 0
	maxValWidth := 0
	maxUnitWidth := 0

	for _, it := range items {
		if len(it.name) > maxNameWidth {
			maxNameWidth = len(it.name)
		}
		if len(it.val) > maxValWidth {
			maxValWidth = len(it.val)
		}
		if len(it.unit) > maxUnitWidth {
			maxUnitWidth = len(it.unit)
		}
	}

	// 对齐打印
	for _, it := range items {
		sb.WriteString(fmt.Sprintf("  %-*s : %*s  %-*s\n",
			maxNameWidth, it.name,
			maxValWidth, it.val,
			maxUnitWidth, it.unit,
		))
	}

	sb.WriteString(fmt.Sprintf("  Count: %d\n", r.Count))

	return sb.String()
}

// WithGVK 为map添加GVK信息
func (r *ResourceMetrics) WithGVK(obj runtime.Object) {
	gvks := obj.GetObjectKind().GroupVersionKind()
	// 某些typed对象可能未携带GVK，这里兜底
	if gvks.Empty() {
		switch obj.(type) {
		case *appsv1.Deployment:
			gvks = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}
		case *appsv1.DaemonSet:
			gvks = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "DaemonSet"}
		case *appsv1.StatefulSet:
			gvks = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"}
		case *batchv1.Job:
			gvks = schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "Job"}
		case *batchv1.CronJob:
			gvks = schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "CronJob"}
		case *batchv1beta1.CronJob:
			gvks = schema.GroupVersionKind{Group: "batch", Version: "v1beta1", Kind: "CronJob"}
		case *corev1.Service:
			gvks = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Service"}
		case *corev1.ConfigMap:
			gvks = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}
		case *corev1.ServiceAccount:
			gvks = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ServiceAccount"}
		case *rbacv1.Role:
			gvks = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "Role"}
		case *rbacv1.RoleBinding:
			gvks = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBinding"}
		case *rbacv1.ClusterRole:
			gvks = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRole"}
		case *rbacv1.ClusterRoleBinding:
			gvks = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"}
		case *corev1.PersistentVolumeClaim:
			gvks = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PersistentVolumeClaim"}
		case *corev1.PersistentVolume:
			gvks = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PersistentVolume"}
		case *corev1.Secret:
			gvks = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Secret"}
		default:
			// 留空也行
		}
	}
	if gvks.Version != "" {
		if gvks.Group == "" {
			r.Version = gvks.Version
		} else {
			r.Version = gvks.Group + "/" + gvks.Version
		}
	}
	if gvks.Kind != "" {
		r.Kind = gvks.Kind
	}
}
